package com.jerry.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import javax.validation.constraints.NotNull;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

@Slf4j
@Component
public class RestTemplateLoggingInterceptor implements ClientHttpRequestInterceptor {

    private final ObjectMapper objectMapper;

    public RestTemplateLoggingInterceptor(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Override
    public ClientHttpResponse intercept(HttpRequest request,
                                        byte[] body,
                                        ClientHttpRequestExecution
                                                execution) throws IOException {
        RequestInfo requestInfo = traceRequest(request, body);
        ClientHttpResponse response = execution.execute(request, body);
        ResponseInfo responseInfo = traceResponse(response);
        /*log.info("call url: {}, method: {}, request: {} ,response: {}",
                request.getURI(),
                request.getMethod().toString(),
                objectMapper.writeValueAsString(requestInfo),
                objectMapper.writeValueAsString(responseInfo));*/
        return response.getStatusCode().is2xxSuccessful() ? response : null;
    }

    private RequestInfo traceRequest(@NotNull HttpRequest request, @NotNull
            byte[] body) {
        RequestInfo requestInfo = new RequestInfo();
        requestInfo.setHeaders(request.getHeaders().toString());
        requestInfo.setBody(body.toString());
        return requestInfo;
    }

    private ResponseInfo traceResponse(@NotNull ClientHttpResponse
                                               httpResponse) throws IOException {
        ResponseInfo responseInfo = new ResponseInfo();
        responseInfo.setStatusCode(httpResponse.getStatusCode().value());
        responseInfo.setStatusText(httpResponse.getStatusText());
        responseInfo.setHeaders(httpResponse.getHeaders().toString());
        StringBuilder inputStringBuilder = new StringBuilder();
        InputStream body = httpResponse.getBody();
        BufferedReader bufferedReader = new BufferedReader(new
                InputStreamReader(body, StandardCharsets.UTF_8));
        String line = bufferedReader.readLine();
        while (line != null) {
            inputStringBuilder.append(line);
            inputStringBuilder.append('\n');
            line = bufferedReader.readLine();
        }
        responseInfo.setBody(inputStringBuilder.toString());
        return responseInfo;
    }

    @Data
    @Accessors(chain = true)
    public static class RequestInfo {
        private String headers;
        private String body;
    }

    @Data
    @Accessors(chain = true)
    public static class ResponseInfo {
        private Integer statusCode;
        private String statusText;
        private String headers;
        private String body;
    }

}
